<?php


namespace app\common\model\order;


use addons\epay\library\Service;
use app\common\model\goods\GoodsModel;
use Exception;
use think\Db;
use think\Model;
use Yansongda\Pay\Pay;

class PayModel extends Model
{

    /**
     * 付款
     *
     * @param int $user_id 用户ID
     * @param int $openid OPENID
     * @param string $platform 平台:pc=PC,mini=微信小程序,app=App
     * @param string $pay_type 支付类型:alipay=支付宝,wxpay=微信,wallet=钱包
     * @param string $order_no 订单号
     */
    public function pay($params, $user_id)
    {
        extract($params);

        Db::startTrans();
        try {
            $user = model('app\common\model\User')->lock(true)->find($user_id);

            if($pay_type == 'wxpay') {
                if(empty($user->openid)) {
                    throw new Exception("请先进行微信授权", 4009);
                }
            }

            $orderMold = 'unique';
            $returnData = [];

            $orderUnique = OrderUniqueModel::get(['unique_order_no' => $order_no]);
            if (!$orderUnique) {
                //** 兼容老版本,订单列表页调取支付(拆单前) 2022-11-30 15:43:37 **//
                $orderInfo = OrderModel::get(['order_no' => $order_no]);
                if (!$orderInfo) {
                    throw new Exception("未找到订单", 44101);
                }
                if ($orderInfo->is_close == 1) {
                    throw new Exception("订单已关闭", 44105);
                }
                if ($orderInfo->is_pay == 1) {
                    throw new Exception("订单已支付", 44102);
                }
                if ($orderInfo->status == 5) {
                    throw new Exception("订单已取消", 44103);
                }
                $orderUnique = OrderUniqueModel::get(['unique_order_no' => $orderInfo->unique_order_no]);
                if (!$orderUnique) {
                    throw new Exception("未找到订单", 44101);
                }
                $order_no = $orderInfo->unique_order_no;
                $orderMold = 'order';
                //****//
            }
            if ($orderUnique->is_pay == 1) {
                throw new Exception("订单已支付", 44102);
            }
            if ($orderUnique->is_pay == -1) {
                throw new Exception("订单已取消", 44103);
            }

            $outTradeNo = $orderUnique->trade_no;
            if($orderMold == 'order') $outTradeNo = OrderNo();

            switch ($pay_type){
                // 钱包支付
                case 'wallet':
                    if($user->money < $orderUnique->need_price){
                        throw new Exception("钱包余额不足", 44106);
                    }
                    // 扣除余额,新增记录
                    \app\common\model\User::money( -$orderUnique->need_price, $user_id, "支出订单:$order_no");

                    $orders = OrderModel::all(['unique_order_no' => $order_no]);
                    foreach ($orders as $order){
                        $order->status = 1;
                        // 发货方式:express=物流快递,ziti=自提
                        if($order->dispatch_type == 'ziti') {
                            $order->status = 2;
                            // 生成取件码
                            $claim_code = strtoupper(CreateUnStr() . CreateRandomStr(6));
                            $order->claim_code = $claim_code;
                            $claim_code_image = (new \app\common\library\WxCode)->createQrcode(['claim_code' => $claim_code,'uid' => $order->user_id],'claimcode');
                            $order->claim_code_image = $claim_code_image;
                        }
                        $order->is_pay = 1;
                        $order->pay_type = 'wallet';
                        $order->pay_price = $order->total_fee;
                        $order->pay_time = time();
                        $order->save();

                        // 生成账单
                        OrderStatementModel::operAdd('order', $order);

                        $oper = [
                            'id' => $order->user_id,
                        ];
                        OrderAction::operAdd($order, null, $oper, 'user', '订单支付成功');

                        // 兑换券创建校验处理
//                        $this->createUserCouponExchange($user_id, $order->id);

                        // 分销处理, 当下单人身份为用户时(group_id==1), 才触发分销
//                        \app\common\model\UserBrokerageLogModel::checkUserBrokerage('order',$order->user_id, $order->id);
                        // TODO 分销处理, 爆款产品才有分销
                        \app\common\model\UserBrokerageLogModel::checkUserBrokerage2($order->user_id, $order->id);
                    }

                    $orderUnique->is_pay = 1;
                    $orderUnique->pay_price = $orderUnique->need_price;
                    $orderUnique->pay_time = time();
                    $orderUnique->save();

                    Db::commit();
                    return [
                        'code' => 200,
                        'msg' => '支付成功',
                        'data' => []
                    ];
                    break;
                // 微信支付
                case 'wxpay':
                    $paytype = 'wechat';
                    switch ($platform){
                        // 小程序支付
                        case 'mini':
                            $method = 'mini';
                            break;
                        case 'pc':
                            $method = 'scan';
                            break;
                        case 'app':
                            break;
                    }
                    if(!$method){
                        Exception('暂不支持该支付方式',44104);
                    }
//                    $outTradeNo = OrderNo();
                    $totalFee = $orderUnique->need_price;
                    $notifyUrl = GetDomain() . '/api/pay/notify/paytype/'.$paytype;
                    $body = '购买商品';
                    if($orderMold == 'order') {
                        $orderUnique->trade_no = $outTradeNo;
                        $orderUnique->save();
                        OrderModel::update(['pay_order_no' => $outTradeNo], ['unique_order_no' => $order_no]);
                    }
                    Db::commit();
                    $params = [
                        'type'         => $paytype,
                        'orderid'      => $outTradeNo,
                        'title'        => $body,
                        'amount'       => $totalFee,
                        'method'       => $method,
                        'openid'       => $openid,
                        'notifyurl'    => $notifyUrl,
                    ];
                    $payInfo = Service::submitOrder($params);
                    if($platform == 'pc'){
                        if (!isset($payInfo['code_url'])) {
                            Exception('创建订单失败，请返回重试',44104);
                        }
                    }
                    $data = [
                        'paytype' => $paytype,
                        'out_trade_no' => $outTradeNo,
                        'order_no' => $order_no,
                        'amount' => $totalFee,
                        'payInfo' => $payInfo
                    ];
                    return [
                        'code' => 200,
                        'msg'  => '请求成功',
                        'data' => $data
                    ];
                    break;
                // 支付宝支付
                case 'alipay':
                    switch ($platform) {
                        case 'app':
                            $paytype = 'alipay';
                            $method = 'app';
//                            $outTradeNo = OrderNo();
                            $totalFee = $orderUnique->need_price;
                            $notifyUrl = GetDomain() . '/api/pay/notify/paytype/'.$paytype;
                            $body = '购买商品';
                            if($orderMold == 'order') {
                                $orderUnique->trade_no = $outTradeNo;
                                $orderUnique->save();
                                OrderModel::update(['pay_order_no' => $outTradeNo], ['unique_order_no' => $order_no]);
                            }
                            Db::commit();
                            $params = [
                                'type'         => $paytype,
                                'orderid'      => $outTradeNo,
                                'title'        => $body,
                                'amount'       => $totalFee,
                                'method'       => $method,
                                'openid'       => $openid,
                                'notifyurl'    => $notifyUrl,
                            ];
                            $payInfo = Service::submitOrder($params);

                            $data = [
                                'order_no' => $order_no,
                                'amount' => $totalFee,
                                'payInfo' => $payInfo
                            ];
                            return [
                                'code' => 200,
                                'msg'  => '请求成功',
                                'data' => $data
                            ];
                            break;
                    }
                    Exception('暂不支持该支付方式',44104);
                    break;
            }

            Db::rollback();
            return [
                'code' => 44100,
                'msg' => '支付失败',
                'data' => []
            ];
        }catch (Exception $e) {
            Db::rollback();
            return [
                'code' => $e->getCode(),
                'msg' => $e->getMessage(),
                'data' => $e->getLine()
            ];
        }
    }

    /**
     * 支付下单回调处理
     */
    public function notify($paytype)
    {
        Db::startTrans();
        $data = [];
        try {
            $pay = \addons\epay\library\Service::checkNotify($paytype);
            if (!$pay) {
                echo '签名错误';
                throw new Exception("签名错误,type:$paytype");
            }
            $data = $pay->verify();

            $this->xmlLog(JsonEn($data));

            //回调处理
            $orderUnique = OrderUniqueModel::get(['trade_no' => $data['out_trade_no']]);
            $orders = OrderModel::all(['pay_order_no' => $data['out_trade_no']]);
            if(!$orderUnique) {
                throw new Exception('未找到订单',44101);
            }
            if($orderUnique->is_pay != 0) {
                throw new Exception('订单已支付',44102);
            }

            $pay_price = 0;
            $pay_time = 0;
            $out_trade_no = 0;
            switch ($paytype){
                case 'wechat':
                    $pay_price = $data['total_fee'] / 100;
                    $pay_time = strtotime($data['time_end']);
                    $out_trade_no = $data['transaction_id'];
                    break;
                case 'alipay':
                    $pay_price = $data['total_amount'];
                    $pay_time = strtotime($data['gmt_payment']);
                    $out_trade_no = $data['trade_no'];
                    break;
            }

            //修改订单状态
            $orderUnique->is_pay = 1;
            $orderUnique->pay_price = $pay_price;
            $orderUnique->pay_time = $pay_time;
            $orderUnique->save();

            foreach ($orders as $order){
                if($order->status != 0) {
                    throw new Exception("订单[{$order->order_no}]状态错误[status={$order->status}]",44107);
                }
                $order->status = 1;
                // 发货方式:express=物流快递,ziti=自提
                if($order->dispatch_type == 'ziti') {
                    $order->status = 2;
                    // 生成取件码
                    $claim_code = strtoupper(CreateUnStr() . CreateRandomStr(6));
                    $order->claim_code = $claim_code;
                    $claim_code_image = (new \app\common\library\WxCode)->createQrcode(['claim_code' => $claim_code,'uid' => $order->user_id],'claimcode');
                    $order->claim_code_image = $claim_code_image;
                }
                $order->is_pay = 1;
                $order->pay_type = $paytype=='wechat'?'wxpay':$paytype;
                $order->pay_time = $pay_time;
                $order->pay_price = $order->total_fee;
                $order->trade_no = $out_trade_no;
                $order->save();

                // 库存扣减方式:place=拍下减库存,pay=付款减库存
                // 扣除库存(付款减库存)
                $order_goods = OrderGoodsModel::field('goods_id,goods_spec_id,num')
                    ->with(['goods' => function($query){
                        $query->where('stock_type','pay');
                    }])
                    ->where(['order_id' => $order->id])
                    ->select();
                if($order_goods){
                    foreach ($order_goods as $row){
                        GoodsModel::updateStock($row->goods_id,$row->goods_spec_id,$row->num);
                    }
                }

                $oper = [
                    'id' => $order->user_id,
                ];
                OrderAction::operAdd($order, null, $oper, 'user', '订单支付成功');

                // 生成账单
                OrderStatementModel::operAdd('order', $order);

                // 兑换券创建校验处理
//                $this->createUserCouponExchange($order->user_id, $order->id);

                // TODO 分销处理, 爆款产品才有分销
//                \app\common\model\UserBrokerageLogModel::checkUserBrokerage('order',$order->user_id, $order->id);
                \app\common\model\UserBrokerageLogModel::checkUserBrokerage2($order->user_id, $order->id);

            }

            Db::commit();

            //你可以在这里你的业务处理逻辑,比如处理你的订单状态、给会员加余额等等功能
            //下面这句必须要执行,且在此之前不能有任何输出
            return $pay->success()->send();
        }catch (Exception $e) {
            Db::rollback();
//            $returnString = '回调失败,订单号:'.empty($data['out_trade_no'])?'':$data['out_trade_no'].',错误码:'.$e->getCode().',错误描述:'.$e->getMessage();
            $returnString = '回调失败,错误码:'.$e->getCode().',错误描述:'.$e->getMessage();
            $this->xmlLog($returnString);
        }
    }


    /**
     * PC扫码支付结果查询
     * @param string $paytype 支付类型:alipay=支付宝,wechat=微信
     * @param string $out_trade_no 订单号
     */
    public function pcPayQuery($params)
    {
        extract($params);
        try {
            switch ($paytype){
                case 'wechat':
                    $config = Service::getConfig($paytype);
                    $pay = Pay::wechat($config);
                    $result = $pay->find($out_trade_no,'scan');
                    if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
                        return [
                            'code' => 200,
                            'msg' => '请求成功',
//                            'data' => $result,
                            'data' => [
                                'out_trade_no' => $result['out_trade_no'],
                                'total_fee' => $result['total_fee'] / 100,
                                'status' => $result['trade_state'],
                                'status_text' => $result['trade_state_desc'],
                            ],
                        ];
                    } else {
                        throw new Exception("查询失败",40002);
                    }
                case 'alipay':
            }
            return [
                'code' => 40002,
                'msg' => '暂不支持支付方式',
                'data' => [],
            ];
        }catch (Exception $e) {
            return [
                'code' => $e->getCode(),
                'msg' => $e->getMessage(),
                'data' => $e->getLine()
            ];
        }
    }


    /**
     * 生成用户兑换券
     *
     */
    public function createUserCouponExchange($user_id, $order_id)
    {
        $create_arr = [];
        $time = time();
        $date = date('Y-m',$time);
        $order = model('app\common\model\order\OrderModel')->get($order_id);
        if($order && $order->is_burst_order == 1 && $order->coupon_exchange_id > 0) {
            $order_goods = model('app\common\model\order\OrderGoodsModel')->where(['order_id' => $order_id])->select();
            foreach ($order_goods as $row) {
                $coupon_exchange = model('app\common\model\CouponExchangeModel')->get($order->coupon_exchange_id);
                if($coupon_exchange) {
                    $mouthRange = $this->getDateRange($date, $coupon_exchange->cycle, $coupon_exchange->start_time_mold);
                    foreach ($mouthRange as $key => $val) {
                        $claim_code = strtoupper(CreateUnStr() . CreateRandomStr(6));
                        $claim_code_image = (new \app\common\library\WxCode)->createQrcode(['claim_code' => $claim_code,'uid' => $order->user_id],'coupon');
                        $create_arr = [
                            'user_id' => $user_id,
                            'order_id' => $order_id,
                            'shop_id' => $order->shop_id,
                            'goods_id' => $row->goods_id,
                            'goods_spec_id' => $row->goods_spec_id,
                            'coupon_exchange_id' => $order->coupon_exchange_id,
                            'start_time' => strtotime($val['firstDate']),
                            'end_time' => strtotime($val['lastDate']),
                            'title' => $coupon_exchange->title,
                            'image' => $coupon_exchange->image,
                            'goods_num' => $coupon_exchange->num,
                            'claim_code' => $claim_code,
                            'claim_code_image' => $claim_code_image,
                            'status' => 1,
                            'createtime' => $time,
                        ];
                        $res = model('app\common\model\UserCouponExchangeModel')->create($create_arr);
                        if($res !== false) {
                            $create_arr['id'] = $res->id;
                            // TODO 创建过期处理任务
                            $queueParams = $create_arr;
                            // 延时执行时间(秒)
                            $queueTime = $create_arr['end_time'] - time();
                            $queue = 'jrbq';
                            // 下单后未支付自动关闭订单操作
                            Queue('app\common\job\CouponExchangeAutoOper@UnusedCouponExchangeOverdue', $queueParams, $queueTime, $queue);
                        }
                    }
                }
            }
        }
    }


    /**
     * 获取兑换日期区间集
     * @param string $date 某个日期
     * @param int $cycle 周期数
     * @param string $start_time_mold 核销开始时间:now=本月,next=次月
     */
    public function getDateRange(string $date, int $cycle, string $start_time_mold): array
    {
        $time_arr = [];
        $start_num = 0;
        if($start_time_mold == 'next') {
            $start_num = 1;
        }else{
            $cycle -= 1;
        }
        for ($i = $start_num; $i <= $cycle; $i++) {
            $firstDate = date('Y-m-d',mktime(00, 00, 00, date('m', strtotime($date)) + $i, 01));
            $lastDate = date('Y-m-d',mktime(23, 59, 59, date('m', strtotime($date)) + ( $i + 1 ), 00));
            $time_arr[] = [
                'firstDate' => $firstDate,
                'lastDate' => $lastDate,
            ];
        }
        return $time_arr;
    }


    protected function xmlLog($str)
    {
        $file_dir = '.././runtime/log/payLog/';
        create($file_dir);
        $file_name = $file_dir.date('Ymd').'.txt';
        fopen($file_name, 'a+');
        $str = PHP_EOL.'[PayLog]'.PHP_EOL.'['.date('Y-m-d H:i:s').']'.PHP_EOL.'[json_data]'.PHP_EOL.$str;
        file_put_contents($file_name,$str,FILE_APPEND);

        \think\Log::write($str);
    }

}